<?php
/**
 * @author root
 *
 */
class RuleFileHelper extends CComponent {
	
	public static function getConfig()
	{
		$str = file_get_contents(Yii::app()->params["rulePath"]."ATTENTION");
		$config = Config::model()->findByPk('attention');
		if($config == null )
			$config = new Config();
		$config->key = "attention";
		$config->value = 0;
		$config->textvalue = $str;
		$config->save();
	}
	public static $IS_REBUILD = false;
	public static function getClass($str)
	{
		$regex = '/classtype:\s*([^;]+);/';
		$matches = array ();
		
		preg_match ( $regex, $str, $matches );
		
		if (count ( $matches ) < 2)
			return null;
		else
			return trim($matches [1]);
	}
	public static function parseConfFile() {
		try {
			$ret = array ();
			$count = 0;
			RuleFileHelper::$IS_REBUILD = true;
			$file = Yii::app()->params["confPath"];
			if(!file_exists($file))
				throw new Exception("cannot open file".$file);
			$handle = fopen ( $file, "r" );

				
			while ( ! feof ( $handle ) ) {
				$line = fgets ( $handle );
				if(strlen($line) < 1)
					continue;
				if ($line [0] === '#')
					continue;
				if (strpos ( $line, 'include $RULE_PATH' ) === false)
					continue;
				{
					$regex = '#/(.*)$#';
					$matches = array ();
					preg_match ( $regex, $line, $matches );
					$ret [$count ++] = Yii::app()->params["rulePath"] . $matches [1];
				}
			}
		} catch ( Exception $e ) {
			return array("ret"=>"0", "info"=>$e->getMessage());
		}
		return RuleFileHelper::updateDBFromFile ( $ret );
	}
	public static function getGid($str) {
		$regex = '/gid:\s*(\d+)/';
		$matches = array ();
		
		preg_match ( $regex, $str, $matches );
		
		if (count ( $matches ) < 2)
			return 1;
		else
			return $matches [1];
	}
	public static function getSid($str) {
		$regex = '/sid:\s*(\d+)/';
		$matches = array ();
		
		preg_match ( $regex, $str, $matches );
		
		if (count ( $matches ) < 2)
			return null;
		else
			return $matches [1];
	}
	public static function getRev($str) {
		$regex = '/rev:\s*(\d+)/';
		$matches = array ();
		
		preg_match ( $regex, $str, $matches );
		
		if (count ( $matches ) < 2)
			return 1;
		else
			return $matches [1];
	}
	
	public static function getFileTimeStamp($filename)
	{
		$RULE_PATH = Yii::app()->params["rulePath"];
		$realtime = filemtime($RULE_PATH.$filename);
		return date("Y-m-d H:i:s",$realtime);
	}
	public static function checkFileTimeStamp()
	{
		$RULE_PATH = Yii::app()->params["rulePath"];
		$categories = RuleCategory::model()->findAll();
		$ret = array('new'=>array(),'old'=>array());
		foreach ($categories as $category) {
			$realtime = filemtime($RULE_PATH.$category->category);
			$dbtime = strtotime($category->modifydate);
			if( $dbtime < $realtime )
			{
				array_push($ret['old'],$category);
			}
			else if($dbtime > $realtime)
			{
				array_push($ret['new'],$category);
			}
		}
		return $ret;
	}
	public static function updateDBFromFile($files) {
		// $connection =
		try {
			$ruleCnt = 0;
			$fileCnt = 0;
			foreach ( $files as $ruleFile ) {
				$found = false;
				$arr = explode ( '/', $ruleFile );
				$name = $arr [count ( $arr ) - 1];
				$catId = - 1;
				$category = RuleCategory::model ()->findByAttributes ( array (
						'category' => $name 
				) );
				if ($category == null) {
					$category = new RuleCategory ();
					$category->category = $name;
					$category->modifydate = date ( "Y-m-d H:i:s", filemtime ( $ruleFile ) );
					$category->save ();
				}
				$catId = $category->id;
				if(!file_exists($ruleFile))
					throw new Exception("cannot open file".$ruleFile);
				$handle = fopen ( $ruleFile, "r" );
				$comment = "";
				while ( ! feof ( $handle ) ) {
					$line = fgets ( $handle );
					if (strlen ( $line ) < 2)
						continue;
					if (strpos ( $line, "event_filter" ) !== false)
						continue;
					if ($line [0] == '#')
						$comment = $comment . $line;
					else {
						$rule = $line;
						$record = Rule::model ()->findByAttributes ( array (
								'sid' => RuleFileHelper::getSid ( $rule ),
								'gid' => RuleFileHelper::getGid ( $rule ) 
						) );
						if ($record == null) {
							$record = new Rule ();
							$record->sid = RuleFileHelper::getSid ( $rule );
							$record->gid = RuleFileHelper::getGid ( $rule );
							$record->revision = RuleFileHelper::getRev ( $rule );
							$record->categoryId = $catId;
							$record->ruleClass = RuleFileHelper::getClass($rule);
						}
						$record->fullcontent = $rule;
						//$comment = iconv ( 'gbk', 'utf-8', $comment );
						$record->rulecomment = $comment;
						if (! $record->save ()) {
							throw new CException ( $record->errors, 1 );
						}
						$comment = "";
						$found = true;
						$ruleCnt ++;
					}
					
				}
				//if($found === true)
				$category->modifydate = date ( "Y-m-d H:i:s", filemtime ( $ruleFile ) );
				$category->save();
			$fileCnt ++;
			}
		} catch ( Exception $e ) {
			if ($e->getCode () == 1) {
				// a db write record occurs
				return array (
						"ret"=>"0","info" => "record write failed: " . $e->getMessage () 
				);
			}
		}
		return array (
				"ret"=>"1","info" => 'Done. total ' . $ruleCnt . ' records inserted, '.$fileCnt." files processed" 
		);
	}
	public static function test() {
		$ret = exec ( "cd /tmp && ./test 2>&1" );
		var_dump ( $ret );
	}
	public static function updateSVN($comment) {
		$RULE_PATH = Yii::app()->params["rulePath"];
		system ( "cd " . $RULE_PATH . " &&  sh test.sh" );
		$cmd = "cd " . $RULE_PATH . " && /usr/bin/svn commit -m '" . $comment . "'";
		$ret = exec ( $cmd, $arr );
		if (! $ret)
			throw new CException ( "svn commit failed:CMD:" . $cmd . " RET:" . var_dump ( $ret ), 1 );
	}
	public static function modifyRuleFile($name, $id) {
		$RULE_PATH = Yii::app()->params["rulePath"];
		$name = $RULE_PATH . $name;
		$tarName = $name . "new";
		#$target = trim ( $target );
		if (file_exists ( $tarName ))
			throw new CException ( "This file is being edited. " );
		$tarHandle = fopen ( $tarName, "w+" );
		$models = Rule::model ()->findAllByAttributes ( array (
				'categoryId' => $id 
		) );
		foreach ( $models as $model ) {
			fputs ( $tarHandle, $model->rulecomment . "\n" );
			fputs ( $tarHandle, $model->fullcontent . "\n" );
		}
		fclose ( $tarHandle );
		unlink ( $name );
		copy ( $tarName, $name );
		unlink ( $tarName );
	}
	public static function addRuleOnFile($target, $name) {
		// FIXME:directory traversal vunerability
		// FIXME:\n issues
		$RULE_PATH = Yii::app()->params["rulePath"];
		$name = $RULE_PATH . $name;
		$tarName = $name . "new";
		$target = trim ( $target );
		if (file_exists ( $tarName ))
			throw new CException ( "This file is being edited. " );
		$srcHandle = fopen ( $name, "a+" );
		fputs ( $srcHandle, $target );
		fclose ( $srcHandle );
		// RuleFileHelper::updateSVN("add rule:".$target);
	}
	public static function modifyRuleOnFile($origin, $target, $name) {
		// FIXME:directory traversal vunerability
		// FIXME:\n issues
		$RULE_PATH = Yii::app()->params["rulePath"];
		if ($target == null || ! isset ( $target ) || $target == "")
			throw new CException ( "check your target argument" );
		$name = $RULE_PATH . $name;
		$tarName = $name . "new";
		$target = trim ( $target );
		if (file_exists ( $tarName ))
			throw new CException ( "This file is being edited. " );
		$srcHandle = fopen ( $name, "r" );
		$tarHandle = fopen ( $tarName, "w+" );
		$found = false;
		while ( ! feof ( $srcHandle ) ) {
			$line = fgets ( $srcHandle );
			if (! $found && ! strcmp ( trim ( $line ), trim ( $origin ) )) {
				$found = true;
				fputs ( $tarHandle, $target . "\n" );
			} else {
				fputs ( $tarHandle, $line );
			}
		}
		fclose ( $srcHandle );
		fclose ( $tarHandle );
		if (! $found) {
			unlink ( $tarName );
			throw new CException ( "The content you want to replace does not exist:" . $origin );
		} else {
			unlink ( $name );
			copy ( $tarName, $name );
			unlink ( $tarName );
		}
		// RuleFileHelper::updateSVN("modify rule: ".$name);
	}
	public static function deleteRuleOnFile($origin, $name) {
		// FIXME:directory traversal vunerability
		// FIXME:\n issues
		$RULE_PATH = Yii::app()->params["rulePath"];
		$name = $RULE_PATH . $name;
		$tarName = $name . "new";
		$target = trim ( $target );
		if (file_exists ( $tarName ))
			throw new CException ( "This file is being edited. " );
		$srcHandle = fopen ( $name, "r" );
		$tarHandle = fopen ( $tarName, "w+" );
		$found = false;
		$debug = "";
		while ( ! feof ( $srcHandle ) ) {
			$line = fgets ( $srcHandle );
			$debug = $debug . "*****src*****: " . $line . "<br>";
			$debug = $debug . "*****ori*****: " . $origin . "<br>";
			if (! $found && ! strcmp ( trim ( $line ), trim ( $origin ) )) {
				$found = true;
				fputs ( $tarHandle, "#" . date ( DATE_RFC822 ) . " deleted by heqidan@baidu.com\n" );
				fputs ( $tarHandle, "#" . $origin . "\n" );
			} else {
				fputs ( $tarHandle, $line );
			}
		}
		fclose ( $srcHandle );
		fclose ( $tarHandle );
		if (! $found) {
			unlink ( $tarName );
			throw new CException ( "The content you want to replace does not exist:" . $origin . " ### " . $debug );
		} else {
			unlink ( $name );
			copy ( $tarName, $name );
			unlink ( $tarName );
		}
		// RuleFileHelper::updateSVN("delete rule in FILE: ".$name);
	}
	public static function removeFileOnSvn($name) {
		$RULE_PATH = Yii::app()->params["rulePath"];
		if (! system ( "cd " . $RULE_PATH . " && svn del " . $name ))
			throw new CException ( "svn del failed" );
	}
	public static function addFileOnSvn($name) {
		$RULE_PATH = Yii::app()->params["rulePath"];
		if (! system ( "cd " . $RULE_PATH . " && svn add " . $name ))
			throw new CException ( "svn add failed" );
	}
	public static function createNewRuleFile($name) {
		$RULE_PATH = Yii::app()->params["rulePath"];
		$name = $RULE_PATH . $name;
		fclose ( fopen ( $name, "w+" ) );
		// RuleFileHelper::addFileOnSvn($name);
	}
}

?>
